HubWrapper = {}

function HubWrapper.getHubs()
    return { peripheral.find("modem") }
end


function HubWrapper.getPeripherals(...)
    local fliter = {}

    for _, f in pairs({...}) do
        fliter[f] = true
    end

    local hubs = { peripheral.find("modem") }

    local result = {}
    
    for _, hub in pairs(hubs) do
        local names = hub.getNamesRemote()
        for _, name in pairs(names) do
            if fliter[hub.getTypeRemote(name)] or false then
                table.insert(result, name)
            end
        end
    end

    return result
end

function HubWrapper.wrap(...)
    local fliter = {}

    for _, f in pairs({...}) do
        fliter[f] = true
    end

    local hubs = { peripheral.find("modem") }

    local result = {}
    
    for _, hub in pairs(hubs) do
        local names = hub.getNamesRemote()
        for _, name in pairs(names) do
            if fliter[name] or false then
                table.insert(result, HubWrapper.wrapAtHub(hub, name))
            end
        end
    end
    return result
end

function HubWrapper.wrapAtHub(hub, name)
    local methods = hub.getMethodsRemote(name)
    if not methods then
        return nil
    end

    -- We store our types array as a list (for getType) and a lookup table (for hasType).
    local types = { hub.getTypeRemote(name) }
    for i = 1, #types do types[types[i]] = true end
    local result = setmetatable({}, {
        __name = "peripheral",
        name = name,
        type = types[1],
        types = types,
    })
    for _, method in ipairs(methods) do
        result[method] = function(...)
            return hub.callRemote(name, method, ...)
        end
    end
    return result
end

return HubWrapper